// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 Ivan Baidakou

#include "board.h"
#include <rotor-light.hpp>

namespace rl = rotor_light;

namespace message {

struct BlinkCommand : rl::Message {
  static constexpr auto type_id = __LINE__;
  using rl::Message::Message;
};

} // namespace message

struct Blinker : rl::Actor<2> {
  using Parent = Actor<2>;

  void initialize() override {
    subscribe(&Blinker::on_blink_command);
    Parent::initialize();
  }

  void advance_start() override {
    Parent::advance_start();
    blink();
  }

  void blink() {
    Board::toggle_led();
    add_event<rl::ctx::thread>(
        delay,
        [](void *data) {
          auto self = static_cast<Blinker *>(data);
          self->send<rl::ctx::thread, message::BlinkCommand>(0, self->id);
        },
        this);
  }

  void on_blink_command(message::BlinkCommand &msg) { blink(); }

  rl::Duration delay;
};

using Storage = rl::traits::MessageStorage<rl::message::ChangeState,
                                           rl::message::ChangeStateAck,
                                           message::BlinkCommand>;
using Queue = rl::Queue<Storage, 5>; /* upto 5 messages in 1 queue */
using Planner = rl::Planner<2>;      /* upto 2 time events */
using Supervisor =
    rl::Supervisor<rl::SupervisorBase::min_handlers_amount, Blinker>;

Supervisor sup;

int main(int, char **) {
  Board::init_start();
  Board::enable_timer();
  ROTOR_LIGHT_ENABLE_INTERRUPTS();

  /* setup */
  Queue queue;
  Planner planner;
  rl::Context context{&queue, &planner, &Board::get_now};
  sup.bind(context);

  auto blinker = sup.get_child<0>();
  blinker->delay = rl::Duration{250000};
  /* let it polls timer */
  sup.start(true);

  /* main cycle */
  sup.process();
  return 0;
}
